use std::{rc::Rc, cell::RefCell, time::Duration};

use crate::{native, rtda::Frame};

pub fn init() {
    native::register("java/lang/Object", "getClass", "()Ljava/lang/Class;", get_class);
    native::register("java/lang/Object", "hashCode", "()I", hash_code);    native::register("java/lang/Object", "hashCode", "()I", hash_code);
    native::register("java/lang/Object", "clone", "()Ljava/lang/Object;", clone);
	native::register("java/lang/Object", "notifyAll", "()V", notify_all);
	native::register("java/lang/Object", "wait", "(J)V", wait);
}

// public final native Class<?> getClass();
// ()Ljava/lang/Class;
fn get_class(frame: Rc<RefCell<Frame>>) {
    // 获取this引用，等同于get_ref(0)
    let this = frame.borrow().get_local_vars().borrow().get_this().unwrap();
    let class = unsafe { &*{&*this}.get_class() }.get_j_class();
    frame.borrow().get_operand_stack().borrow_mut().push_ref(class);
}

// public native int hashCode();
// ()I
fn hash_code(frame: Rc<RefCell<Frame>>) {
    // 获取this引用，等同于get_ref(0)
    let this = frame.borrow().get_local_vars().borrow().get_this().unwrap();
    let hash = this as i32;
    frame.borrow().get_operand_stack().borrow_mut().push_int(hash);
}

// protected native Object clone() throws CloneNotSupportedException;
// ()Ljava/lang/Object;
fn clone(frame: Rc<RefCell<Frame>>) {
    // 获取this引用，等同于get_ref(0)
    let this = frame.borrow().get_local_vars().borrow().get_this().unwrap();
    unsafe {
        let this_class =  { &*this }.get_class();
        let cloneable = this_class.get_class_loader().unwrap().lock().unwrap().load_class("java/lang/Cloneable".to_string());
        if !{ &*this_class }.is_implements(&*cloneable) {
            panic!("java.lang.CloneNotSupportedException")
        }
        let new = Box::into_raw(Box::new({ &mut *this }.clone()));
        frame.borrow().get_operand_stack().borrow_mut().push_ref(Some(new));
    }
}

// public final native void notifyAll();
// ()V
fn notify_all(frame: Rc<RefCell<Frame>>) {
    // TODO
}


// public final native void wait(long timeout) throws InterruptedException;
// ()V
fn wait(frame: Rc<RefCell<Frame>>) {
    // TODO
    // let timeout = frame.borrow().get_operand_stack().borrow_mut().pop_long();

    std::thread::sleep(Duration::from_secs(1));
}